unit sci.simplifier;

interface

uses
  sci.term, sci.log, Dialogs, Variants;

type
  TSimplifier = class
  public
    class function Simplify(expr: String): String;     overload;
    class function Simplify(list: TTermList): TTermList;   overload;
    class function Format(expr: string): String; (*
                                            * Format the expression so that
                                            * the parser can understand it.
                                            *)
  end;

implementation

class function TSimplifier.Simplify(expr: string): String;
var
  tp: TTermParser;
  tl: TTermList;
  i, j: integer;
begin
  tp := TTermParser.Create;
  tp.setStrExpression(expr);
  tl := tp.parse;

  (* Merge the terms *)
  for i := 1 to tl.cnt do
  begin
    if tl.terms[i].coefficient = 0 then continue;
    for j := i + 1 to tl.cnt do
    begin
      if tl.terms[j].coefficient = 0 then continue;
      if tl.terms[i].TermAsStr <> tl.terms[j].TermAsStr then continue;
      tl.terms[i].Merge(tl.terms[j]);
      tl.Remove(tl.terms[j]);
    end;
  end;

  Result := tl.Format;
end;

class function TSimplifier.Simplify(list: TTermList): TTermList;
var
  tl: TTermList;
  i, j: integer;
begin
  tl := TTermList.Create;
  tl.Assign(list);

  (* Merge the terms *)
  for i := 1 to tl.cnt do
  begin
    if tl.terms[i].coefficient = 0 then continue;
    for j := i + 1 to tl.cnt do
    begin
      if tl.terms[j].coefficient = 0 then continue;
      if tl.terms[i].TermAsStr <> tl.terms[j].TermAsStr then continue;
      tl.terms[i].Merge(tl.terms[j]);
      tl.Remove(tl.terms[j]);
    end;
  end;

  Result := tl;
end;

class function TSimplifier.Format(expr: string): String;
  function isAlpha(c: char): boolean;
  begin
    Result := ((c >= 'A') and (c <= 'Z')) or ((c >= 'a') and (c <= 'z'));
  end;

  function isDigit(c: char): boolean;
  begin
    Result := ((c >= '0') and (c <= '9'));
  end;

var
  i: integer;
begin
  i := 0;
  Result := expr;
  while i < length(Result) do
  begin
    inc(i);
    if (isAlpha(Result[i]) or isDigit(Result[i]) or (Result[i] = ')')) and
      (isAlpha(Result[i + 1]) or (Result[i + 1] ='(')) then
      insert('*', Result, i + 1);
  end;
end;

end.
